import logging
from functools import wraps
from typing import Callable, TypeVar, cast

from flask import Blueprint, current_app, request
from flask import jsonify

from airflow.patsnap.service import project_service
from airflow.models.idata_project import Project
from airflow.www.api import provide_user, exception_handle

log = logging.getLogger(__name__)

T = TypeVar("T", bound=Callable)  # pylint: disable=invalid-name


def requires_authentication(function: T):
    """Decorator for functions that require authentication"""

    @wraps(function)
    def decorated(*args, **kwargs):
        return current_app.api_auth.requires_authentication(function)(*args, **kwargs)

    return cast(T, decorated)


api_speech_project = Blueprint('api_speech_project', __name__)


# user route
@api_speech_project.route('/projects/<int:id>', methods=['GET'])
@exception_handle
def get_project(id):
    project = Project.get_project(id)
    return jsonify(code=0, message='ok', data=Project.to_json(project))


# 获取所有项目
@api_speech_project.route('/projects', methods=['GET'])
@exception_handle
def get_projects():
    page = request.args.get('page', 0, type=int)
    result = project_service.get_projects(page)
    return jsonify(code=0, message='ok', data=result)


# 获取所有项目
@api_speech_project.route('/projects/options', methods=['GET'])
@exception_handle
def get_project_options():
    result = project_service.get_project_options()
    return jsonify(code=0, message='ok', data=result)


@api_speech_project.route('/projects', methods=['POST'])
@provide_user
@exception_handle
def add_project(oa_user_name):
    project = request.json
    project_name = None
    project_desc = None
    if 'project_name' in project:
        project_name = project['project_name']
    else:
        log.error("project_name params error project_name={%s}", project_name)
        return jsonify(code=400, message="project_name params has None,", data=None)
    if 'project_desc' in project:
        project_desc = project['project_desc']
    else:
        log.error("project_desc params error project_desc={%s}", project_desc)
        return jsonify(code=400, message="project_desc params has None,", data=None)
    pool = 'default'

    project_service.add_project(project_name, project_desc, oa_user_name, pool)
    return jsonify(code=0, message='ok', data=None)


@api_speech_project.route('/projects/<int:id>', methods=['DELETE'])
@exception_handle
def delete_project(id):
    result = project_service.delete_project(id)
    if result:
        return result
    return jsonify(code=0, message='ok', data=None)


@api_speech_project.route('/projects', methods=['PUT'])
@exception_handle
@provide_user
def update_project(oa_user_name):
    project = request.json
    project_id = project.get('id', None)
    project_name = project.get('project_name', None)
    project_desc = project.get('project_desc', None)
    pool = project.get('pool', None)
    create_by = project.get('create_by', None)
    if project_id is None:
        log.error("id params error project_name={%s}", project_id)
        return jsonify(code=400, message="id params has None,", data=None)
    rs = project_service.update_project(project_id, project_name, project_desc, 0, create_by, pool, oa_user_name)
    if rs:
        return rs
    return jsonify(code=0, message='ok', data=None)


@api_speech_project.route('/projects/<int:id>/users', methods=['GET'])
@exception_handle
def get_project_users(id):
    page = request.args.get('page', 0, type=int)
    result = project_service.get_project_users(id, page)
    return jsonify(code=0, message='ok', data=result)


@api_speech_project.route('/projects/<int:project_id>/users', methods=['POST'])
@exception_handle
@provide_user
def add_project_users(oa_user_name, project_id):
    users = request.json
    if users is None:
        log.error("add_project_users error users=%s", users, )
        return jsonify(code=400, message="add_project_users error users=None", data=None)
    result = project_service.add_project_users(oa_user_name, project_id, users)
    return jsonify(code=0, message='ok', data=result)


@api_speech_project.route('/projects/<int:id>/users', methods=['DELETE'])
@exception_handle
def delete_project_users(id):
    users = request.json
    result = project_service.delete_project_users(id, users)
    return jsonify(code=0, message='ok', data=result)

